﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Activities;
using Microsoft.Xrm.Sdk;
using Moq;
using Microsoft.Xrm.Sdk.Workflow;

namespace XRM.Framework.Test.Unit
{
    #region enums

    public enum WorkflowCategory
    {
        Workflow = 0,
        Dialog = 1
    }

    #endregion

    public abstract class WFActivityUnitTest : XrmUnitTest
    {
        #region Properties

        protected Mock<IWorkflowContext> WorkflowContextMock
        {
            get;
            set;
        }

        protected IWorkflowContext WorkflowContext
        {
            get
            {
                return WorkflowContextMock.Object;
            }
        }

        protected Mock<IOrganizationService> OrganizationServiceMock
        {
            get;
            set;
        }

        protected IOrganizationService OrganizationService
        {
            get
            {
                return OrganizationServiceMock.Object;
            }
        }

        protected Activity WFActivity
        {
            get;
            private set;
        }

        protected Exception Error
        {
            get;
            private set;
        }

        protected IDictionary<string, object> Outputs
        {
            get;
            private set;
        }

        #endregion
        
        #region Constructors

        public WFActivityUnitTest()
        {
            Init();
        }

        #endregion

        #region Protected Methods

        protected virtual void Init()
        {
            OrganizationServiceMock = new Mock<IOrganizationService>();
            WorkflowContextMock = new Mock<IWorkflowContext>();

            InitWorkflowContextMock(WorkflowContextMock);

            OrganizationServiceFactoryMock.Setup(factory => factory.CreateOrganizationService(WorkflowContext.UserId)).Returns(OrganizationService);
            InitOrganizationServiceMock(OrganizationServiceMock);
        }

        protected void InitWorkflowContextMock(Mock<IWorkflowContext> mock)
        {
            mock.Setup(context => context.BusinessUnitId).Returns(Guid.NewGuid());
            mock.Setup(context => context.CorrelationId).Returns(Guid.NewGuid());
            mock.Setup(context => context.Depth).Returns(0);
            mock.Setup(context => context.InitiatingUserId).Returns(Guid.NewGuid());
            mock.Setup(context => context.InputParameters).Returns(new ParameterCollection());
            mock.Setup(context => context.IsExecutingOffline).Returns(false);
            mock.Setup(context => context.IsInTransaction).Returns(false);
            mock.Setup(context => context.IsOfflinePlayback).Returns(false);
            mock.Setup(context => context.MessageName).Returns(string.Empty);
            mock.Setup(context => context.OperationCreatedOn).Returns(DateTime.Now);
            mock.Setup(context => context.OperationId).Returns(Guid.NewGuid());
            mock.Setup(context => context.OrganizationId).Returns(Guid.NewGuid());
            mock.Setup(context => context.OrganizationName).Returns(string.Empty);
            mock.Setup(context => context.OutputParameters).Returns(new ParameterCollection());
            mock.Setup(context => context.OwningExtension).Returns(new EntityReference());
            mock.Setup(context => context.PostEntityImages).Returns(new EntityImageCollection());
            mock.Setup(context => context.PreEntityImages).Returns(new EntityImageCollection());
            mock.Setup(context => context.PrimaryEntityId).Returns(Guid.NewGuid());
            mock.Setup(context => context.PrimaryEntityName).Returns(string.Empty);
            mock.Setup(context => context.RequestId).Returns(Guid.NewGuid());
            mock.Setup(context => context.SecondaryEntityName).Returns(string.Empty);
            mock.Setup(context => context.SharedVariables).Returns(new ParameterCollection());
            mock.Setup(context => context.UserId).Returns(Guid.NewGuid());
            mock.Setup(context => context.StageName).Returns(string.Empty);
            mock.Setup(context => context.WorkflowCategory).Returns((int)WorkflowCategory.Workflow);
        }

        protected IDictionary<string, object> Execute(Activity crmActivity)
        {
            WorkflowInvoker invoker = new WorkflowInvoker(crmActivity);
            
            invoker.Extensions.Add(TracingService);
            invoker.Extensions.Add(WorkflowContext);
            invoker.Extensions.Add(OrganizationServiceFactory);
            
            return invoker.Invoke();
        }
        protected virtual void Test()
        {
            WFActivity = Setup();

            WorkflowInvoker invoker = new WorkflowInvoker(WFActivity);

            invoker.Extensions.Add(TracingService);
            invoker.Extensions.Add(WorkflowContext);
            invoker.Extensions.Add(OrganizationServiceFactory);

            try
            {
                Outputs = invoker.Invoke();
            }
            catch (Exception ex)
            {
                Error = ex;
            }

            Verify();
        }

        #endregion

        #region Abstract Methods

        protected abstract Activity Setup();
        protected abstract void Verify();

        #endregion
    }
}
